﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization;

namespace Airport
{
    [DataContract]
    public class WorldVector
    {
        private float _x, _y, _z;

        public WorldVector()
        {
            _x = 0;
            _y = 0;
            _z = 0;
        }

        public WorldVector(float x, float y, float z)
        {
            _x = x;
            _y = y;
            _z = z;
        }

        public WorldVector(Node node)
        {
            _x = node.XPos;
            _y = node.YPos;
            _z = 0;
        }

        public WorldVector(Node start, Node end)
        {
            _x = end.XPos - start.XPos;
            _y = end.YPos - start.YPos;
            _z = 0; // Since Nodes are in 2-D, Z will be 0
        }

        // Constructor for creating a vector from a plane's current
        // PositionVector to a Node
        public WorldVector(WorldVector start, Node end)
        {
            _x = end.XPos - start._x;
            _y = end.YPos - start._y;
            _z = 0; // Since Nodes are in 2-D, Z will be 0
        }

        public WorldVector(WorldVector start, WorldVector end)
        {
            _x = end._x - start._x;
            _y = end._y - start._y;
            _z = end._z - start._z;
        }

        public WorldVector Times(float s)
        { 
            // scale
            return new WorldVector(_x * s, _y * s, _z * s);
        }       

        public WorldVector Plus(WorldVector v)
        {
            return new WorldVector(_x + v._x, _y + v._y, _z + v._z);
        }        

        public override String ToString()
        {
            return "[X: " + String.Format("{0:0.00}", _x) + ", Y: " + String.Format("{0:0.00}", _y) + ", Z: " + String.Format("{0:0.00}", _z) + "]";
        }

        [DataMember]
        public float X
        {
            get { return _x; }
            set { _x = value; }
        }

        [DataMember]
        public float Y
        {
            get { return _y; }
            set { _y = value; }
        }

        [DataMember]
        public float Z
        {
            get { return _z; }
            set { _z = value; }
        }

        public double Magnitude
        {
            get
            {
                return Math.Sqrt((_x * _x) + (_y * _y) + (_z * _z));
            }
        }

        public WorldVector UnitVector
        {
            get
            {
                float unitX, unitY, unitZ;

                unitX = (float)(_x / this.Magnitude);
                unitY = (float)(_y / this.Magnitude);
                unitZ = (float)(_z / this.Magnitude);

                return new WorldVector(unitX, unitY, unitZ);
            }
        }

        public float Direction
        {
            get
            {
                if (_y == 0)
                {
                    if (_x >= 0)
                    {
                        return 90;
                    }
                    else
                    {
                        return 270;
                    }
                }
                else if (_x == 0)
                {
                    if (_y <= 0)
                    {
                        return 0;
                    }
                    else
                    {
                        return 180;
                    }
                }
                else
                {
                    // Take the arc tan of -y to compensate for coordinate system
                    double radians = Math.Atan2(_x, -_y);
                    double angle = radians * (180 / Math.PI);

                    if (angle < 0)
                    {                                                
                        angle += 360;
                    }

                    return (float)angle;
                }
            }
        }

        /// <summary>
        /// Returns the straight-line distance to a given Node.
        /// </summary>
        /// <param name="other"></param>
        /// <returns>Straight-line distance to the given Node.</returns>
        public double DistanceToNode(Node other)
        {
            double xDifference, yDifference;
            double xSquared, ySquared;

            xDifference = _x - other.XPos;
            yDifference = _y - other.YPos;

            xSquared = xDifference * xDifference;
            ySquared = yDifference * yDifference;

            return Math.Sqrt(xSquared + ySquared);
        }
    }
}
